package tw.cuttle.process;

import java.lang.reflect.Method;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import tw.cuttle.ActionHelper;
import tw.cuttle.CuttleContext;
import tw.cuttle.bean.ActionException;
import tw.cuttle.bean.Process;
import tw.cuttle.bean.ProcessException;
import tw.cuttle.handler.ProcessHandler;

public abstract class MethodInvokeSupport {
    private static Log logger=LogFactory.getLog(MethodInvokeSupport.class);
    protected abstract Object getBean(String exec);
    private void execute(String execStr) throws Exception{
	String execs[] = execStr.split(",");
	for (String exec : execs) {
	    if(exec.equals(CuttleContext.getActionContext().getExecutedProcesses().get(exec))){
		continue;
	    }
	    int pointOffset=exec.lastIndexOf('.');
	    String prefix=exec.substring(0, pointOffset);
	    Object business = getBean(prefix);
	    String methodStr = exec.substring(exec.indexOf(".") + 1, exec.length());
	    Class businessClass = business.getClass();
	    Class[] parameterClasses = new Class[] { ActionHelper.class };
	    if (!CuttleContext.getBeanHolder().getSetting().getEnv().getHelper().equals(
		    ActionHelper.class.getName())) {
		parameterClasses = new Class[] { Class.forName(CuttleContext.getBeanHolder().getSetting()
			.getEnv().getHelper()) };
	    }
	    Method method = businessClass.getMethod(methodStr, parameterClasses);
	    Object[] parameters = new Object[] { CuttleContext.getActionContext().getActionHelper() };
	    method.invoke(business, parameters);
	    CuttleContext.getActionContext().getExecutedProcesses().put(exec, exec);
	}
    }
    public void methodInvoke(ProcessException processException){
	if(processException.getExec()!=null){
	    try{
	    execute(processException.getExec());
	    }catch(Exception e){
		e.printStackTrace();
		throw new RuntimeException(e);
		
	    }
	}
    }
    public void methodInvoke(Process process) {
	try {
	    if (process.getExec() != null) {
		execute(process.getExec());
	    }
	} catch (NoSuchMethodException e) {
	    e.printStackTrace();
	} catch (Exception e) {
	    while (e.getCause() != null) {
		e = (Exception) e.getCause();
	    }
	    e.printStackTrace();
	    if (!executeProcessException(e, process)) {
		if (!executeActionException(e)) {
		    if (!executeGlobalProcessException(e, process)) {
			if (!executeGlobalActionException(e)) {
			    executeCommonActionException(e);
			}
		    }
		}
	    }
	}
    }

    private static void executeCommonActionException(Exception e) {
	List<ActionException> actionExceptions = CuttleContext.getBeanHolder().getGlobalActionExceptions();
	if (actionExceptions != null && !actionExceptions.isEmpty()) {
	    for (int i = 0; i < actionExceptions.size(); i++) {
		ActionException actionException = (ActionException) actionExceptions.get(i);
		if (actionException.getType().equals(Exception.class.getName())) {
		    CuttleContext.getActionContext().getActionHelper()
			    .actionForward(actionException.getActionForward());
		}
	    }
	}

    }

    private static boolean executeActionException(Exception e) {
	List<ActionException> actionExceptions = CuttleContext.getBeanHolder().getGlobalActionExceptions();
	if (actionExceptions != null && !actionExceptions.isEmpty())
	    for (int i = 0; i < actionExceptions.size(); i++) {
		ActionException actionException = (ActionException) actionExceptions.get(i);
		String causeException = e.getClass().getName();
		if (causeException.equals(actionException.getType())) {
		    CuttleContext.getActionContext().getActionHelper()
			    .actionForward(actionException.getActionForward());
		    return true;
		}
	    }
	return false;
    }

    private static boolean executeProcessException(Exception e, Process process) {

	List<ProcessException> processExceptions = process.getExceptions();
	if (processExceptions != null)
	    for (int i = 0; i < processExceptions.size(); i++) {
		ProcessException processException = (ProcessException) processExceptions.get(i);
		String causeException = e.getClass().getName();

		if (causeException.equals(processException.getType())) {
		    ProcessHandler processHandler = new ProcessHandler();
		    processHandler.executeException(processException);
		    return true;
		}
	    }
	return false;
    }

    private static boolean executeGlobalActionException(Exception e) {
	List<ActionException> actionExceptions = CuttleContext.getBeanHolder().getGlobalActionExceptions();
	if (actionExceptions != null && !actionExceptions.isEmpty()) {
	    for (int i = 0; i < actionExceptions.size(); i++) {
		ActionException actionException = (ActionException) actionExceptions.get(i);
		String causeException = e.getClass().getName();
		if (actionException.getType().equals(causeException)) {
		    CuttleContext.getActionContext().getActionHelper()
			    .actionForward(actionException.getActionForward());
		    return true;
		}
	    }
	}
	return false;
    }

    private static boolean executeGlobalProcessException(Exception e, Process process) {

	List<ProcessException> processExceptions = CuttleContext.getBeanHolder().getProcessExceptions(process);
	if (processExceptions != null && !processExceptions.isEmpty())
	    for (int i = 0; i < processExceptions.size(); i++) {
		ProcessException processException = (ProcessException) processExceptions.get(i);
		String causeException = e.getClass().getName();

		if (causeException.equals(processException.getType())) {
		    ProcessHandler processHandler = new ProcessHandler();
		    processHandler.executeException(processException);
		    return true;
		}
	    }
	return false;
    }
}
